package com.linshidream.intrachat.simplenio.pipeline.boots;

import com.linshidream.intrachat.simplenio.pipeline.context.MiniChannel;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.util.Queue;

/**
 * Created on 2025/8/18 18:21
 *
 * @author linshidream
 * @version 1.0.0
 * @description
 */

public class MiniReaderWriter {
    /**
     * 负责读通道中的数据
     *
     * @param ch
     */
    public static void doRead(MiniChannel ch) {

        // 这里设置为每次最多读 1个字节, 缓冲区最大 8kb()
        // 如果只能读到半包, 那么等待下次继续
        // 如果读到粘包, 那么会拆成 List<String> message

        ByteBuffer buffer = ByteBuffer.allocate(7);

        try {
            // 读取的字节长度 循环读
            int len;
            while ((len = ch.socketChannel().read(buffer)) > 0) {
                buffer.flip();
                ByteBuffer accumulate = ch.accumulate(buffer);

                // 交给责任链第一环 解析不到数据立刻结束了
                ch.receive(accumulate);

                buffer.clear();
            }

            if (len == -1) {
                ch.inactive();
            }
        } catch (Exception e) {
            ch.exception(e);
        }
    }


    /**
     * 负责写数据到通道
     * @param sc
     * @throws IOException
     */
    public static void doWrite(MiniChannel sc) throws IOException {
        Queue<ByteBuffer> writeQueue = sc.outQueue();
        while (!writeQueue.isEmpty()) {
            // 查看队头的元素 但是不移除
            ByteBuffer buf = writeQueue.peek();
            int len = sc.socketChannel().write(buf);

            // 当缓冲区写不进去了 监听写事件，等待下次触发
            if (len == 0) {
                System.out.println("当前 Socket 缓冲区写不下去了，开启写监听事件");
                sc.socketChannel().register(sc.selector(), SelectionKey.OP_WRITE);
                return;
            }

            // 缓冲区写完，并且buf全部写完 可以移除元素
            if (!buf.hasRemaining()) {
                writeQueue.poll();
            }
        }

        // 找到这个通道注册在监听器的 key; 取消 OP_WRITE 事件监听
        SelectionKey key = sc.socketChannel().keyFor(sc.selector());
        if (key != null) {
            key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
        }
    }

}
